
import os
import time
import json
import threading

import redis
import paho.mqtt.client as mqtt
from util import get_mac_address
from serial_connect import SerialPortMethod
from crc import crc16_modbus
from command_parse import CommandParse

from setting import *


import logging

logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')

logger = logging.getLogger(__name__)


class MQTTClient:

    def __init__(self, broker_address, broker_port, client_name):
        self.client = mqtt.Client(client_name)
        self.broker_address = broker_address
        self.broker_port = broker_port
        
        # 设置连接成功和消息接收的回调函数
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message

        self.r = redis.Redis(host='localhost', port=6379, db=0)

        # 开启上交数据线程

        self.publish_senor_info_thread = threading.Thread(target=self.publish_senor_info)


    # 连接成功的回调函数
    def on_connect(self, client, userdata, flags, rc):
        print("Connected with result code " + str(rc))

        mac = get_mac_address()

        # 订阅MQTT Topic
        self.client.subscribe(MQTT_DATA_CENTER_TX_TOPIC)

        logger.info("订阅MQTT Topic: {}".format(MQTT_DATA_CENTER_TX_TOPIC))

        
    # 接收MQTT消息的回调函数
    def on_message(self, client, userdata, msg):

        per_msg = json.loads(msg.payload.decode())

        logger.info("MQTT接收信息：{}  {}".format(msg.topic, per_msg))

        if per_msg.get("task_type") == "test":

            self.client.publish(MQTT_DATA_CENTER_RX_TOPIC, json.dumps({"mac": MAC}))

            logger.info("MQTT回调数据:")

            logger.info({"mac": MAC})

        if per_msg.get("task_type") == "set_sensor_light":

            result = {
                "type": "callback",
                "data": {
                    "task_type": "set_sensor_light",
                    "task_id": per_msg.get("task_id"),
                    "task_status": "receive", # 井下主站接受响应该任务
                    "notes": None,
                    "result": None
                }
            }

            self.client.publish(MQTT_DATA_CENTER_RX_TOPIC, json.dumps(result))

            for devaddr in per_msg['data']['devaddr_list']:

                command = f"E5 14 0000 12 {devaddr.zfill(4)} 06 {per_msg['data']['value'].zfill(8)}"

                command = command + crc16_modbus(command)

                logger.info(f"生成下发指令：{command}")

                self.r.rpush(SEND_STATION_COMMAND_STACK, command)



            logger.info("MQTT回调数据:")

            logger.info(result)

        if per_msg.get("task_type") == "set_sensor_light":

            result = {
                "type": "callback",
                "data": {
                    "task_type": "set_sensor_light",
                    "task_id": per_msg.get("task_id"),
                    "task_status": "receive", # 井下主站接受响应该任务
                    "notes": None,
                    "result": None
                }
            }

            self.client.publish(MQTT_DATA_CENTER_RX_TOPIC, json.dumps(result))

            for devaddr in per_msg['data']['devaddr_list']:

                command = f"E5 14 0000 12 {devaddr.zfill(4)} 06 {per_msg['data']['value'].zfill(8)}"

                command = command + crc16_modbus(command)

                logger.info(f"生成下发指令：{command}")

                self.r.rpush(SEND_STATION_COMMAND_STACK, command)



            logger.info("MQTT回调数据:")

            logger.info(result)

        if per_msg.get("task_type") == "set_reporting_cycle":

            result = {
                "type": "callback",
                "data": {
                    "task_type": "set_reporting_cycle",
                    "task_id": per_msg.get("task_id"),
                    "task_status": "receive", # 井下主站接受响应该任务
                    "notes": None,
                    "result": None
                }
            }

            self.client.publish(MQTT_DATA_CENTER_RX_TOPIC, json.dumps(result))

            for devaddr in per_msg['data']['devaddr_list']:

                command = f"E5 14 0000 10 {devaddr.zfill(4)} 06 {str(int(per_msg['data']['value'], 16)).zfill(8)}"

                command = command + crc16_modbus(command)

                logger.info(f"生成下发指令：{command}")

                self.r.rpush(SEND_STATION_COMMAND_STACK, command)

            logger.info("MQTT回调数据:")

            logger.info(result)

        if per_msg.get("task_type") == "read_reporting_cycle":

            result = {
                "type": "callback",
                "data": {
                    "task_type": "read_reporting_cycle",
                    "task_id": per_msg.get("task_id"),
                    "task_status": "receive", # 井下主站接受响应该任务
                    "notes": None,
                    "result": None
                }
            }

            self.client.publish(MQTT_DATA_CENTER_RX_TOPIC, json.dumps(result))

            for devaddr in per_msg['data']['devaddr_list']:

                command = f"E5 14 0000 10 {devaddr.zfill(4)} 03 00000000"

                command = command + crc16_modbus(command)

                logger.info(f"生成下发指令：{command}")

                self.r.rpush(SEND_STATION_COMMAND_STACK, command)

            logger.info("MQTT回调数据:")

            logger.info(result)


    # 连接MQTT Broker
    def connect(self):

        self.client.connect(self.broker_address, self.broker_port, 60)

        self.client.loop_forever()

    # 发布消息到MQTT Topic
    def publish_message(self, topic, message):

        self.client.publish(topic, message)

    def publish_senor_info(self):

        logger.info("开启日常数据提交线程")

        while True:

            try:

                item = self.r.blpop(STATION_DATA_STACK) # 取出提交的数据

                command = item[1].decode()

                parse_data = CommandParse(command).parse_result

                result = {
                    "type": "senorInfo",
                    "data": {
                        "devaddr": 1,
                        "text": command,
                        "parse_data": parse_data
                    }
                }

                topic = f"iot/devices/test/baina/{MAC}/allinone/rx"

                self.client.publish(topic, json.dumps(result))

            except Exception as e:

                logger.error(f"提交传感器信息错误：{str(e)}")
                logger.error(item)

                time.sleep(5)

            else:

                logger.info("topic:{}：提交数据：{}".format(topic, result))





def run_mqtt_client():
    
    mqtt_client = MQTTClient(broker_address="47.110.239.14", broker_port=1883, client_name="cabinet-{}".format(get_mac_address()))

    mqtt_client.publish_senor_info_thread.start()

    mqtt_client.connect()



if __name__ == "__main__":


    run_mqtt_client()